Since 2015, JavaScript has improved immensely.
It’s much more pleasant to use it now than ever.
In this article, we’ll look at new OOP features in JavaScript.
How to use __proto__?
To get the prototype of an object, we use Object.getPrototypeOf
.
To create an object with a given prototype, we can use Object.create
.
Object.setPrototypeOf
is deprecate and it prevents optimizations in many browsers.
__proto__
can be used to get and set the prototype of an object.
Enumerability
The for-in loop traverses the string keys of an own and inherited enumerable properties.
Object.keys
returns the string keys of an enumerable own properties.
JSON.stringify
only stringified enumerable own properties and string keys.
In ES6, Object.assign
only copies enumerable own string and symbol properties.
There’re many non-enumerable properties in a JavaScript object.
All prototype
properties of built-in classes are non-enumerable.
For instance, if we have:
const desc = Object.getOwnPropertyDescriptor.bind(Array);
console.log(desc(Object.prototype, 'toString').enumerable)
We get the property descriptors in the Array.prototype.toString
method.
And we get the enumerable
property, and it’ll log false
.
Marking Properties as not to be Copied
We can mark a property not to be copied if we mark the property as being enumerable.
For instance, we can write:
const obj = Object.defineProperty({}, 'foo', {
value: 'bar',
enumerable: false
});
We set the enumerable
property to false
so that it won’t be picked up by Object.assign
or the spread operator.
**Object.assign()**
Object.assign
can be used to merge object sources into the target.
All own enumerable properties from the sources will be copied to the target.
It doesn’t consider inherited properties.
Hiding Own Properties from JSON.stringify()
Hiding own properties from JSON.stringify
can be done by making properties non-enumerable.
This will make JSON.stringify
skip the properties.
We can also specify the toJSON
method to return the object we want to stringify.
For example, we can write:
const obj = {
foo: 'bar',
toJSON() {
return {
bar: 'baz'
};
},
};
console.log(JSON.stringify(obj))
Then the console log will log {“bar”:”baz”}
.
Customizing Basic Language Operations via Well-Known Symbols
We can customize basic language operations with well-known symbols.
The Symbol.hasInstance
method lets an object customize the behavior of the instanceof
operator.
Symbol.toPrimitive
is a method that lets us customize how it’s converted to a primitive value.
The Symbol.toStringTag
method lets us call Object.prototype.toString
to compute the string description of an object.
Symbol.unscopables
lets us hide some properties from the with
statement.
obj instanceof C
works by doing some checks.
If C
isn’t an object, then it throws a TypeError
.
If the method exists, then it calls C[Symbol.hasInstance](obj)
.
It coerces the result to boolean and returns it.
Otherwise, it computes and returns the result according to the regular algorithm by checking for scalability, C.prototype
in the prototype chain of obj
, etc.
The only method in the standard library that has Symbol.hasInstance
is Function.prototype
.
We can check whether a value in an object by writing:
const ObjType = {
[Symbol.hasInstance](value) {
return (value !== null &&
(typeof value === 'object' ||
typeof value === 'function'));
}
};
We create our own ObjType
object with the Symbol.hasInstance
method.
It takes the value
we want to check.
Then it checks whether it’s not bull
, the type of value
is 'object'
or 'function'
.
Then we can use it by writing:
{} instanceof ObjType
which returns true
.
Conclusion
Enumerabnility of objects can be changed and checked.
Also, we can change the behavior or instanceof
and other operators by overriding methods with well-known symbols.